using System;
using System.Linq;
using NHibernate;
using NHibernate.Linq;
using FluentNHibernate;
using FluentNHibernate.Mapping;

public class Persistence {
    public static FluentNHibernate.Cfg.FluentConfiguration configureDB() {
        return
            FluentNHibernate.Cfg.Fluently.Configure(
                new NHibernate.Cfg.Configuration()).
            Mappings(
                m => m.FluentMappings.AddFromAssemblyOf<Beer>());
    }
    public static void buildSchema(NHibernate.Cfg.Configuration config) {
        new NHibernate.Tool.hbm2ddl.SchemaExport(config).
            SetOutputFile("ddl.sql").
            SetDelimiter(";").
            Create(false, true);
    }

    public static void rebuildDB() {
        using (var factory =
               configureDB().
               ExposeConfiguration(buildSchema).
               BuildSessionFactory()) {
            using (var s = factory.OpenSession()) {
                var ABV = new Double [] {4.82, 4.25, 5.5, 4.5};
                Beer someBeer = null;
                foreach (var dt in
                         Enumerable.Select(
                             new [] {
                                 "2009-08-10T12:00:00Z",
                                 "2009-08-10T02:00:00Z",
                                 "2009-08-10T08:00:00Z",
                                 "2009-08-10T14:32:00Z",
                                 "2009-08-10T16:00:00Z"},
                             d => DateTime.Parse(d))) {
                    foreach (var days in Enumerable.Range(0, 10)) {
                        foreach (var v in new [] {"lager", "pilsener", "ale", "ipa", "stout", "weissbier"}) {
                            someBeer =
                                new Beer {
                                    Variety = v,
                                    BrewDate = dt.AddDays(days),
                                    ABV = ABV[Math.Abs(v.GetHashCode()) % ABV.Length]};
                            s.Save(someBeer);
                        }
                    }
                }
                for (int i = 0; i < 128; ++i) {
                    s.Save(
                        new Bottle {
                            Serial = i,
                            Contents = someBeer});
                }
                s.Flush();
            }
        }
    }

    public static ISessionFactory makeSessionFactory() {
        return configureDB().BuildSessionFactory();
    }

    //TODO: choose a new class so that we can
    // have member access expressions in the
    // constructor below.
    public class BeerMap : ClassMap<Beer> {
        public BeerMap() {
            CompositeId().
                KeyProperty(x => x.Variety).
                KeyProperty(x => x.BrewDate);
            Map(x => x.ABV);
        }
    }
    public class BottleMap : ClassMap<Bottle> {
        public BottleMap() {
            Id(x => x.Serial);
            References(x => x.Contents).Columns(b => b.Variety, b => b.BrewDate);
        }
    }
}
